####什么是数值微分？其实就是利用自变量微小的差值来进行求导数值，这就是数值微分，这其实和求导数的基本原理是相通的，想象自变量的变化无限趋近于0时，因变量的变化
import numpy as np
import matplotlib.pylab as plt
#数值微分，一种不好的代码实现方式
def numerical_diff_1(f,x):
    h = 10e-50  #试图使用这个0.000....1(小数点后50个0)来表示那种微小的变化，不过这里不行，编译器无法表示到那么小的数字
    return (f(x+h)-f(x))/h  #这里也不太得行，因为这里表示的是f(x+h)和f（x）之间连线的斜率，虽然这个h很小，但是这条连线的斜率和f（x）切线的斜率还是有差距

#数值微分，稍有优化的版本
def numerical_diff_2(f,x):
    h = 1e-4  #数值虽然相较之前大了很多，但是编译器可以表示出来了呀
    return (f(x+h) - f(x-h))/(2*h)  #前面用的是前向差分，我们这里用中心差分，比前向差分更准确一些吧，应该

#构建切线方程
def tangent_line(f,x):
    k = numerical_diff_2(f,x)  #根据数值微分得到切线的斜率
    d = f(x) - k*x
    return lambda t: k*t + d

#例子1函数
def function_1(x):
    return 0.01*x**2 + 0.1*x

if __name__ == '__main__':
    ##画一下例子1函数图像来看看
    x = np.arange(0.0,20.1,0.1) #以0.1为单位,从0到20的数组x
    y = function_1(x)
    tf = tangent_line(function_1,5) #数值为5时，原函数的切线方程
    ty = tf(x)

    plt.xlabel("x")
    plt.ylabel("f(x)")
    plt.plot(x,y)
    plt.plot(x,ty)
    plt.show()
    #使用数值微分的方式计算一下x=5，x=10时的导数
    xd_1 = numerical_diff_2(function_1,5) #0.1999999999990898
    xd_2 = numerical_diff_2(function_1,10) #0.2999999999986347
    print(xd_1)
    print(xd_2)